package com.sy.socket.test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Map;
import java.util.regex.Matcher;

/**
 * 
 * @author Administrator
 * 模拟上传文件的请求
 *
 */
public class SocketClient {
	/**
	 * http1.1请求体格式:
	 * 请求行
	 * 请求头
	 * 回车换行
	 * 请求体
	 */
	
	//回车换行符
	private static final String NEWLINE = "\r\n";
	//边界前缀
	private static final String BOUNDARY_PREFIX = "--";
	//自定义边界分隔符
	private static final String BOUNDARY = "--------scytest";
	
	//请求行
	private static final String REQUESTLINE = "POST %s HTTP/1.1";
	
	//请求头内容定义
	//请求头host
	private static final String HOST = "Host: %s:%s";
	//请求类型
	private static final String CONTENTTYPE = "Content-Type: multipart/form-data; boundary="+BOUNDARY;
	//请求长度
	private static final String CONTENTLENGTH = "Content-Length: %d";

	//创建Socket连接端
	public Socket targetServer(String host,int port) throws UnknownHostException, IOException {
		return new Socket(host, port);
	}
	
	public byte[] httpRequest(Map<String,Object> params,Map<String,String> fileMap,String uri,Socket clientSocket) {
		try(clientSocket){
			OutputStream os = clientSocket.getOutputStream();
			PrintWriter w = new PrintWriter(os);
			// 1. 写入请求行 requestLine
			w.write(String.format(REQUESTLINE, uri));
			w.write(NEWLINE);
			
			//2.组装请求体，计算请求体大小
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			params.entrySet().forEach(e ->{
				byte[] byteArr = addFormData(e.getKey(),e.getValue());
				try {
					baos.write(byteArr);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			});
			
			fileMap.entrySet().forEach(fm ->{
				byte[] byteArr = addFormFile(fm.getKey(),fm.getValue());
				try {
					baos.write(byteArr);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			});
			String lastBoundary = NEWLINE+BOUNDARY_PREFIX+BOUNDARY;
			baos.write(lastBoundary.getBytes());
			
			byte[] bodyByteArr = baos.toByteArray();
			
			//3.写入请求体
			w.write(String.format(HOST,"127.0.0.1",8000));//域名
			w.write(NEWLINE);
			w.write(String.format(CONTENTLENGTH, bodyByteArr.length));//请求体长度
			w.write(NEWLINE);
			w.write(CONTENTTYPE);
			w.write(NEWLINE);
			
			//4.回车换行
			w.write(NEWLINE);
			w.flush();
			
			//5.请求体
			os.write(bodyByteArr);
			
			os.flush();
			
			clientSocket.shutdownOutput();
			return clientSocket.getInputStream().readAllBytes();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	@SuppressWarnings("resource")
	private byte[] addFormFile(String key, String path) {
		String[] split = path.split("/");
		String fileName = split[split.length-1];
		StringBuffer sb = new StringBuffer();
		sb.append(BOUNDARY_PREFIX+BOUNDARY)//现有分界符
		.append(NEWLINE)
		.append("Content-Disposition: form-data; name=\"")
		.append(key)
		.append("\"; ")
		.append("filename=\"")
		.append(fileName)
		.append("\"")
		.append(NEWLINE)
		.append("Content-Type: application/octet-stream")
		.append(NEWLINE)
		.append(NEWLINE) //两个回车换行
		;
		//请求文件内容
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		
		try {
			outputStream.write(sb.toString().getBytes());
			outputStream.write(new FileInputStream(path).readAllBytes());
			outputStream.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return outputStream.toByteArray();
	}


	private byte[] addFormData(String key, Object value) {
		StringBuffer sb = new StringBuffer();
		sb.append(BOUNDARY_PREFIX+BOUNDARY)//现有分界符
		.append(NEWLINE)
		.append("Content-Disposition: form-data; name=\"")
		.append(key)
		.append("\"")
		.append(NEWLINE).append(NEWLINE) //两个回车换行
		.append(value)//属性值
		.append(NEWLINE);//最后回车换行
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try {
			baos.write(sb.toString().getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return baos.toByteArray();
	}

	public static void main(String[] args) throws UnknownHostException, IOException {
		SocketClient socketClient = new SocketClient();
		Socket targetServer = socketClient.targetServer("127.0.0.1", 8080);
		byte[] httpRequest = socketClient.httpRequest(Map.of("id","1","name","zhangsan"), Map.of("file","D:/Backup/Documents/20220707.rar"), "/j/upload", targetServer);
		System.out.println(new String(httpRequest));
		
	}
	
}
